import { IApiItem } from '@/utils/interfaces'
import { mock } from '@/utils/mock'
import {
    defualtReqContextVars,
    getCurrentExpect,
    getVarContext,
} from '@/utils/variableHandlers'
import { Alert, Button, Message, Space } from '@arco-design/web-react'
import JSON5 from 'json5'
import { camelCase } from 'lodash-es'
import { editor } from 'monaco-editor'
import React, { useEffect, useRef, useState } from 'react'
import { jsonToMock } from '../..//utils/jsonSchemaToMock'
import Editor, { IEditorRef } from '../../components/Editor/Editor'

interface IApiHandlerEditProps {
    // updateKey，当updateKey变化时更新内部value
    updateKey?: string
    // 值
    value?: string
    // api数据
    apiItem?: IApiItem
    // 值发生变化
    onChange?: (value: string) => void
    // 添加变量
    onAddVariable?: (name: string, type: IVariableType) => void
}

const ApiHandlerEdit: React.FC<IApiHandlerEditProps> = ({
    updateKey,
    value: propsValue,
    apiItem,
    onChange: propsOnChange,
    onAddVariable,
}) => {
    // 编辑器的实例
    const editorRef = useRef<IEditorRef | null>(null)
    // 预览的实例
    const previewRef = useRef<IEditorRef | null>(null)
    // 编辑器错误提示
    const [error, setError] = useState<string | undefined>()
    // mock错误提示
    const [mockError, setMockError] = useState<string | undefined>()

    // 格式化
    const format = () => {
        if (!editorRef.current) {
            return
        }
        const editorValue = editorRef.current.getValue()
        try {
            // 获取值
            // 格式化
            const result = JSON.stringify(JSON5.parse(editorValue), null, 2)
            editorRef.current.setValue(result)
            setError(undefined)
            return
        } catch (error) {
            console.log(error)
        }
        setError('格式化失败，你输入的可能不是有效的JSON，请检查内容是否正确')
    }

    // 点击刷新预览
    const refreshPreview = () => {
        if (!editorRef.current || !previewRef.current) {
            return
        }
        // 获取值
        const editorValue = editorRef.current.getValue()
        setMockError(undefined)
        const result = mock(editorValue, {
            onError: (error) => {
                console.log(error)
                setMockError('mock失败，请检查内容是否正确')
            },
            varContext: {
                ...defualtReqContextVars,
                ...getVarContext(getCurrentExpect(apiItem)?.variables),
            },
        })
        if (!result) {
            return
        }
        previewRef.current.setValue(result)
    }

    // JSON转MockJS
    const handleJsonToMockjs = () => {
        if (!editorRef.current) {
            return
        }
        // 先格式化
        format()
        // 拿到值
        const editorValue = editorRef.current.getValue()
        // 转MockJS模板
        try {
            // 获取json值
            const jsonValue = JSON5.parse(editorValue)
            // 转MockJS模板
            const mockjsTemplate = jsonToMock(jsonValue)
            // 设置值
            editorRef.current.setValue(JSON.stringify(mockjsTemplate, null, 2))
        } catch (error) {
            console.log(error)
        }
    }

    // 失焦后
    const handleBlur = () => {
        let value = editorRef.current?.getValue() || ''
        try {
            format()
            value = editorRef.current?.getValue() || ''
        } catch (error) {
            console.log(error)
        }
        propsOnChange?.(value)
    }

    // 值发生变化
    useEffect(() => {
        editorRef.current?.setValue(propsValue || '')
        setError(undefined)
        setMockError(undefined)
    }, [propsValue, updateKey])

    // 编辑器挂在完成后
    const handleEditorMount = (editor: editor.IStandaloneCodeEditor) => {
        // 添加右键菜单：提取到变量
        editor.addAction({
            id: 'extract-to-variable',
            label: '提取到变量',
            contextMenuGroupId: 'navigation',
            contextMenuOrder: 1.5,
            run: (ed) => {
                const selection = ed.getSelection()
                console.log('选中的文本', selection)
                const isSelectedText =
                    selection?.startColumn !== selection?.endColumn
                // 如果有选中的则使用选中的，否则使用当前行
                if (!selection) {
                    return
                }
                const selectedText = isSelectedText
                    ? ed.getModel()?.getValueInRange(selection)
                    : ed.getModel()?.getLineContent(selection.startLineNumber)
                // 如果不存在，或则选中了多行，则不处理
                if (!selectedText || selectedText.includes('\n')) {
                    Message.info('仅支持单行提取')
                    return
                }
                // 匹配属性名和值 "propName": propValue
                const propertyPattern = /^"([^"]+)"\s*:\s*(.+)$/
                const match = selectedText.trim().match(propertyPattern)

                if (!match) {
                    Message.info('未匹配到有效的JSON属性')
                    return
                }
                const propertyName = match[1] // 属性名
                const propertyValue = match[2].replace(/,$/, '').trim() // 属性值（去掉末尾逗号）
                // 准备好新的属性名和值
                let newPropertyName = `${propertyName}`
                let newPropertyValue = `"!{{${propertyName}}}"`
                let varName = propertyName
                let varType: IVariableType = 'string'
                // 如果内容是数组，则变量改成长度
                if (propertyValue.startsWith('[')) {
                    varType = 'number'
                    newPropertyName = propertyName.split('|')[0] || propertyName
                    varName = camelCase(newPropertyName) + 'Len'
                    newPropertyName = `${newPropertyName}|!{{${varName}}}`
                    newPropertyValue = propertyValue
                } else if (propertyValue.startsWith('"')) {
                    varName = camelCase(propertyName)
                    newPropertyValue = `"!{{${varName}}}"`
                } else {
                    if (propertyValue === 'true' || propertyValue === 'false') {
                        varType = 'boolean'
                    } else if (propertyValue === 'null') {
                        varType = 'null'
                    } else if (!isNaN(Number(propertyValue))) {
                        varType = 'number'
                    } else {
                        varType = 'string'
                    }
                }
                // 新内容
                const newContent = selectedText
                    .replace(propertyName, newPropertyName)
                    .replace(propertyValue, newPropertyValue)
                // 将选中的内容替换为新内容
                if (selection) {
                    const range = isSelectedText
                        ? selection
                        : {
                              startLineNumber: selection.startLineNumber,
                              startColumn: 0,
                              endLineNumber: selection.startLineNumber,
                              endColumn: selectedText.length + 1,
                          }

                    ed.executeEdits('extract-to-variable', [
                        {
                            range,
                            text: newContent,
                        },
                    ])
                }
                onAddVariable?.(varName, varType)
            },
        })
    }

    return (
        <div className='flex w-full mb-[200px]'>
            {/* 编辑器 */}
            <div className='w-3/5'>
                {!!error && (
                    <div className='pr-2'>
                        <Alert type='error' content={error} />
                    </div>
                )}
                <div className='my-2 pr-2 flex justify-between'>
                    编辑
                    <Space>
                        <Button onClick={handleJsonToMockjs} size='small'>
                            JSON转MockJS
                        </Button>
                        <Button onClick={format} size='small'>
                            格式化
                        </Button>
                    </Space>
                </div>
                <Editor
                    editorRef={editorRef}
                    language='json'
                    defaultValue={propsValue || ''}
                    onBlur={handleBlur}
                    onMount={handleEditorMount}
                />
            </div>
            {/* 预览 */}
            <div className='w-2/5'>
                {!!mockError && (
                    <div>
                        <Alert type='error' content={mockError} />
                    </div>
                )}
                <div className='my-2 flex justify-between'>
                    预览
                    <div>
                        <Button onClick={refreshPreview} size='small'>
                            刷新
                        </Button>
                    </div>
                </div>
                <Editor
                    language='json'
                    editorRef={previewRef}
                    options={{
                        lineNumbersMinChars: 2,
                        readOnly: true,
                        wrappingIndent: 'indent',
                        wordWrap: 'on',
                        tabSize: 2,
                        insertSpaces: true,
                    }}
                    defaultValue={''}
                />
            </div>
        </div>
    )
}

export default ApiHandlerEdit
